{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center>\n",
    "<img src=\"../../img/ods_stickers.jpg\">\n",
    "## Открытый курс по машинному обучению\n",
    "</center>\n",
    "Авторы материала: Data Science интерн Ciklum, студент магистерской программы CSDS UCU Виталий Радченко, программист-исследователь Mail.ru Group, старший преподаватель Факультета Компьютерных Наук ВШЭ Юрий Кашницкий. Материал распространяется на условиях лицензии [Creative Commons CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). Можно использовать в любых целях (редактировать, поправлять и брать за основу), кроме коммерческих, но с обязательным упоминанием автора материала."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# <center> Тема 5. Композиции алгоритмов, случайный лес</center>\n",
    "## <center> Часть 3. Важность признаков</center>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Очень часто вы хотите понять свой алгоритм, почему он именно так, а не иначе дал определенный ответ. Или если не понять его полностью, то хотя бы какие переменные больше всего влияют на результат. Из случайного леса можно довольно просто получить данную информацию.\n",
    "\n",
    "### Суть метода\n",
    "\n",
    "По данной картинке интуитивно понятно, что важность признака «Возраст»  в задаче кредитного скоринга выше, чем важность признака «Доход» . Формализуется это с помощью понятия прироста информации.\n",
    "<img src=\"../../img/credit_scoring_toy_tree.gif\" align='center'>\n",
    "\n",
    "Если построить много деревьев решений (случайный лес), то чем выше в среднем признак в дереве решений, тем он важнее в данной задаче классификации/регрессии. При каждом разбиении в каждом дереве улучшение критерия разделения (в нашем случае коэффициент Джини) — это показатель важности, связанный с переменной разделения, и накапливается он по всем деревьям леса отдельно для каждой переменной.\n",
    "\n",
    "Давайте немного углубимся в детали. Среднее снижение точности, вызываемое переменной, определяется во время фазы вычисления out-of-bag ошибки. Чем больше уменьшается точность предсказаний из-за исключения (или перестановки) одной переменной, тем важнее эта переменная, и поэтому переменные с бо́льшим средним уменьшением точности более важны для классификации данных. Среднее уменьшение коэффициента Джини (или ошибки mse в задачах регрессии) является мерой того, как каждая переменная способствует однородности узлов и листьев в окончательной модели случайного леса. Каждый раз, когда отдельная переменная используется для разбиения узла, коэффициент Джини для дочерних узлов рассчитывается и сравнивается с коэффициентом исходного узла. Коэффициент Джини является мерой однородности от 0 (однородной) до 1 (гетерогенной). Изменения в значении критерия разделения суммируются для каждой переменной и нормируются в конце вычисления. Переменные, которые приводят к узлам с более высокой чистотой, имеют более высокое снижение коэффициента Джини.\n",
    "\n",
    "А теперь представим все вышеописанное в виде формул. \n",
    "$$ \\large VI^{T} = \\frac{\\sum_{i \\in \\mathfrak{B}^T}I \\Big(y_i=\\hat{y}_i^{T}\\Big)}{\\Big |\\mathfrak{B}^T\\Big |} - \\frac{\\sum_{i \\in \\mathfrak{B}^T}I \\Big(y_i=\\hat{y}_{i,\\pi_j}^{T}\\Big)}{\\Big |\\mathfrak{B}^T\\Big |} $$\n",
    "\n",
    "$ \\large \\hat{y}_i^{(T)} = f^{T}(x_i)  $ — предсказание класса перед перестановкой/удалением признака\n",
    "$ \\large \\hat{y}_{i,\\pi_j}^{(T)} = f^{T}(x_{i,\\pi_j})   $ — предсказание класса после перестановки/удаления признака\n",
    "$ \\large x_{i,\\pi_j} = (x_{i,1}, \\dots , x_{i,j-1}, \\quad x_{\\pi_j(i),j}, \\quad x_{i,j+1}, \\dots , x_{i,p})$\n",
    "Заметим, что $ \\large VI^{(T)}(x_j) = 0 $, если $ \\large X_j $  не находится в дереве $ \\large T $ \n",
    "\n",
    "Расчет важности признаков в ансамбле:\n",
    "— ненормированные \n",
    "$$ \\large VI(x_j) = \\frac{\\sum_{T=1}^{N}VI^{T}(x_j)}{N} $$\n",
    "\n",
    "— нормированные \n",
    "$$ \\large z_j = \\frac{VI(x_j)}{\\frac{\\hat{\\sigma}}{\\sqrt{N}}} $$\n",
    "**Пример.**\n",
    "\n",
    "Рассмотрим результаты анкетирования посетителей хостелов с сайтов Booking.com и TripAdvisor.com. Признаки — средние оценки по разным факторам (перечислены ниже) — персонал, состояние комнат и т.д. Целевой признак — рейтинг хостела на сайте.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import division, print_function\n",
    "\n",
    "# отключим всякие предупреждения Anaconda\n",
    "import warnings\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "%matplotlib inline\n",
    "import seaborn as sns\n",
    "\n",
    "# russian headres\n",
    "from matplotlib import pyplot as plt\n",
    "from matplotlib import rc\n",
    "\n",
    "font = {\"family\": \"Verdana\", \"weight\": \"normal\"}\n",
    "rc(\"font\", **font)\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.ensemble import RandomForestRegressor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hostel_data = pd.read_csv(\"../../data/hostel_factors.csv\")\n",
    "features = {\n",
    "    \"f1\": u\"Персонал\",\n",
    "    \"f2\": u\"Бронирование хостела \",\n",
    "    \"f3\": u\"Заезд в хостел и выезд из хостела\",\n",
    "    \"f4\": u\"Состояние комнаты\",\n",
    "    \"f5\": u\"Состояние общей кухни\",\n",
    "    \"f6\": u\"Состояние общего пространства\",\n",
    "    \"f7\": u\"Дополнительные услуги\",\n",
    "    \"f8\": u\"Общие условия и удобства\",\n",
    "    \"f9\": u\"Цена/качество\",\n",
    "    \"f10\": u\"ССЦ\",\n",
    "}\n",
    "\n",
    "forest = RandomForestRegressor(n_estimators=1000, max_features=10, random_state=0)\n",
    "\n",
    "forest.fit(hostel_data.drop([\"hostel\", \"rating\"], axis=1), hostel_data[\"rating\"])\n",
    "importances = forest.feature_importances_\n",
    "\n",
    "indices = np.argsort(importances)[::-1]\n",
    "# Plot the feature importancies of the forest\n",
    "num_to_plot = 10\n",
    "feature_indices = [ind + 1 for ind in indices[:num_to_plot]]\n",
    "\n",
    "# Print the feature ranking\n",
    "print(\"Feature ranking:\")\n",
    "\n",
    "for f in range(num_to_plot):\n",
    "    print(\n",
    "        \"%d. %s %f \"\n",
    "        % (f + 1, features[\"f\" + str(feature_indices[f])], importances[indices[f]])\n",
    "    )\n",
    "plt.figure(figsize=(15, 5))\n",
    "plt.title(u\"Важность конструктов\")\n",
    "bars = plt.bar(\n",
    "    range(num_to_plot),\n",
    "    importances[indices[:num_to_plot]],\n",
    "    color=([str(i / float(num_to_plot + 1)) for i in range(num_to_plot)]),\n",
    "    align=\"center\",\n",
    ")\n",
    "ticks = plt.xticks(range(num_to_plot), feature_indices)\n",
    "plt.xlim([-1, num_to_plot])\n",
    "plt.legend(bars, [u\"\".join(features[\"f\" + str(i)]) for i in feature_indices]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "На рисунке выше видно, что люди больше всего обращают внимание на персонал и соотношение цена/качество и на основе впечатления от данных вещей пишут свои отзывы. Но разница между этими признаками и менее влиятельными признаками не очень значительная, и выкидывание какого-то признака приведет к уменьшению точности нашей модели. Но даже на основе нашего анализа мы можем дать рекомендации отелям в первую очередь лучше готовить персонал и/или улучшить качество до заявленной цены. \n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
